PROGRAM factorial
! ------------------------------------------------------------------------------
! Programmer:     Jonathan Landrum
!
! Purpose:        This program demonstrates a more efficient factorial algorithm
!
! Assumptions:    GCC GFortran is installed on the compiling machine
! 
! Revisions:      Date           Programmer          Description of Change
!                 ===========    ================    ========================
!                 30 Oct 2012    Jonathan Landrum    Original code.
! ------------------------------------------------------------------------------
    
    IMPLICIT NONE
    
    ! DATA DICTIONARY: Declared variables
    INTEGER,PARAMETER :: k32      = selected_int_kind(32) ! Integer kind
    INTEGER(kind=k32) :: input    = 0                     ! Input variable
    INTEGER(kind=k32) :: output   = 1                     ! Output variable
    INTEGER           :: counter  = 1                     ! Counter variable
    CHARACTER         :: response = 'Y'                   ! Continue variable
    
    ! Introduce the program
    WRITE (*,*) '* * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
    WRITE (*,*) '*                                                       *'
    WRITE (*,*) '*              Fortran Factorial Calculator             *'
    WRITE (*,*) '*                                                       *'
    WRITE (*,*) '* * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
    WRITE (*,*)
    WRITE (*,*) 'This program demonstrates a faster algorithm for finding'
    WRITE (*,*) 'factorials. It does so without using recursion.'
    WRITE (*,*)
    WRITE (*,*) '---------------------------------------------------------'
    WRITE (*,*)
    
    ! Continue loop
    DO WHILE (response == 'y' .OR. response == 'Y')
    
        ! Set variables for repeat loops (or you'll get janky results)
        input   = 0
        output  = 1
        counter = 1
        
        ! Prompt the user for number to calculate
        WRITE (*,'(a)',advance='no') ' Enter a number to calculate: '
        READ  (*,*) input
        WRITE (*,*)
        
        ! Guarantee sane inputs
        DO WHILE (input < 1)
            WRITE (*,*) '<< ERROR: BAD INPUT >>'
            WRITE (*,'(a)',advance='no') ' Enter a number to calculate: '
            READ  (*,*) input
            WRITE (*,*)
        END DO
        
        ! Get the case for 0
        WRITE (*,*) 0, '! = ', output
        
        ! Have to check for negative output because it gets big quick
        DO WHILE ((output .GT. 0) .AND. (counter .LE. input))
            WRITE (*,*) counter, '! = ', output
            counter = counter + 1
            output  = output * counter
        END DO
        
        ! Prompt the user to continue or exit
        WRITE (*,*)
        WRITE (*,'(1X,A49)',advance='no') 'Would you like to calculate another value? [Y/N] '
        READ  (*,*) response
        WRITE (*,*)
    
    END DO ! END "continue" loop
    WRITE (*,*) '---------------------------------------------------------'
    WRITE (*,*) '\\//_ Live long and prosper.'
END PROGRAM factorial